import './ScrollableArea.styl';

import React, { Component } from 'react';
import { Icon } from '../../icons';
import PropTypes from 'prop-types';
import getScrollbarSize from '../../utils/getScrollbarSize.js';
import throttled from '../../utils/throttled.js';
class ScrollableArea extends Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
    class: PropTypes.string,
    scrollableClass: PropTypes.string,
    scrollX: PropTypes.bool,
    scrollY: PropTypes.bool,
    hideScrollbar: PropTypes.bool,
    scrollStep: PropTypes.number,
    onScrollMounted: PropTypes.func,
  };

  static defaultProps = {
    hideScrollbar: false,
    class: 'flex-grow fit',
    scrollY: true,
    scrollX: false,
    scrollStep: 100,
  };

  constructor(props) {
    super(props);

    this.state = {
      scrollAreaClasses: '',
    };

    this.scrollHandlerThrottled = throttled(500, this.scrollHandler);
    this.updateScrollHandlerThrottled = throttled(2000, this.scrollHandler);
  }

  setScrollableElement = element => {
    this.scrollableElement = element;
    if (this.props.onScrollMounted) {
      this.props.onScrollMounted(this);
    }
  };

  render() {
    let scrollableClass = 'scrollable';
    if (this.props.scrollableClass) {
      scrollableClass += ` ${this.props.scrollableClass}`;
    }
    if (this.props.scrollX) {
      scrollableClass += ` scrollX`;
    }
    if (this.props.scrollY) {
      scrollableClass += ` scrollY`;
    }

    return (
      <div
        className={`scrollArea ${this.props.class} ${this.state.scrollAreaClasses}`}
      >
        <div
          className={scrollableClass}
          ref={this.setScrollableElement}
          onScroll={this.scrollHandlerThrottled}
          onMouseEnter={this.scrollHandlerThrottled}
          onTransitionEnd={this.scrollHandlerThrottled}
        >
          {this.props.children}
        </div>
        <div className="scrollNav scrollNavUp" onClick={this.scrollNavUp}>
          <Icon name="angle-double-up" />
        </div>
        <div className="scrollNav scrollNavDown" onClick={this.scrollNavDown}>
          <Icon name="angle-double-down" />
        </div>
        <div className="scrollNav scrollNavLeft" onClick={this.scrollNavLeft}>
          <Icon name="angle-double-left" />
        </div>
        <div className="scrollNav scrollNavRight" onClick={this.scrollNavRight}>
          <Icon name="angle-double-right" />
        </div>
      </div>
    );
  }

  componentDidMount() {
    this.adjustMargins();
    this.scrollHandler();
    window.addEventListener('resize', this.adjustMargins);
  }

  componentDidUpdate() {
    this.adjustMargins();
    this.updateScrollHandlerThrottled();
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.adjustMargins);
  }

  scrollNavDown = event => {
    const {
      scrollTop: currentTop,
      offsetHeight: height,
      scrollHeight,
    } = this.scrollableElement;

    const limit = scrollHeight - height;
    let scrollTop = currentTop + this.props.scrollStep;
    scrollTop = scrollTop > limit ? limit : scrollTop;
    // this.scrollableElement.scrollTop = scrollTop;
    this.scrollableElement.scrollTo({ top: scrollTop, behavior: 'smooth' });
  };

  scrollNavUp = event => {
    const { scrollTop: currentTop } = this.scrollableElement;

    let scrollTop = currentTop - this.props.scrollStep;
    scrollTop = scrollTop < 0 ? 0 : scrollTop;

    // this.scrollableElement.scrollTop = scrollTop;
    this.scrollableElement.scrollTo({ top: scrollTop, behavior: 'smooth' });
  };

  scrollNavLeft = event => {
    const { scrollLeft: currentLeft } = this.scrollableElement;

    let scrollLeft = currentLeft - this.props.scrollStep;
    scrollLeft = scrollLeft < 0 ? 0 : scrollLeft;

    // this.scrollableElement.scrollLeft = scrollLeft;
    this.scrollableElement.scrollTo({ left: scrollLeft, behavior: 'smooth' });
  };

  scrollNavRight = event => {
    const {
      scrollLeft: currentLeft,
      offsetWidth: width,
      scrollWidth,
    } = this.scrollableElement;

    const limit = scrollWidth - width;
    let scrollLeft = currentLeft + this.props.scrollStep;
    scrollLeft = scrollLeft > limit ? limit : scrollLeft;
    // this.scrollableElement.scrollLeft = scrollLeft;
    this.scrollableElement.scrollTo({ left: scrollLeft, behavior: 'smooth' });
  };

  scrollToActiveItem = item => {
    if (item) {
      const scrollMargin = 8;
      if (this.props.scrollY) {
        this.scrollableElement.scrollTo({
          top: item.offsetTop - scrollMargin,
          behavior: 'smooth',
        });
      } else if (this.props.scrollX) {
        this.scrollableElement.scrollTo({
          left: item.offsetLeft - scrollMargin,
          behavior: 'smooth',
        });
      }
    }
  };

  adjustMargins = () => {
    if (this.props.hideScrollbar) {
      const x = this.props.scrollX ? 1 : 0;
      const y = this.props.scrollY ? 1 : 0;
      const scrollbarSize = getScrollbarSize();
      this.scrollableElement.style.marginRight = `${0 -
        scrollbarSize[0] * y}px`;
      this.scrollableElement.style.marginBottom = `${0 -
        scrollbarSize[1] * x}px`;
    }
  };

  scrollHandler = () => {
    if (this.scrollableElement) {
      const {
        offsetHeight: height,
        scrollTop,
        scrollHeight,
        offsetWidth: width,
        scrollLeft,
        scrollWidth,
      } = this.scrollableElement;
      let scrollAreaClasses = '';

      // Check if can scroll up
      if (scrollTop) {
        scrollAreaClasses += ' canScrollUp';
      }

      // Check if can scroll down
      if (scrollTop + height + 1 < scrollHeight) {
        scrollAreaClasses += ' canScrollDown';
      }

      if (scrollLeft) {
        scrollAreaClasses += ' canScrollLeft';
      }

      if (scrollLeft + width + 1 < scrollWidth) {
        scrollAreaClasses += ' canScrollRight';
      }

      if (this.state.scrollAreaClasses !== scrollAreaClasses) {
        this.setState({
          scrollAreaClasses,
        });
      }
    }
  };
}

export default ScrollableArea;
